/**
 * Title:       PlatformConfigReader.java
 * Copyright:   Copyright (c) 1996-2004 The Agent Factory Working Group. All rights reserved.
 * Licence:     This file is free software; you can redistribute it and/or modify
 *              it under the terms of the GNU Lesser General Public License as published by
 *              the Free Software Foundation; either version 2.1, or (at your option)
 *              any later version.
 *
 *              This file is distributed in the hope that it will be useful,
 *              but WITHOUT ANY WARRANTY; without even the implied warranty of
 *              MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *              GNU Lesser General Public License for more details.
 *
 *              You should have received a copy of the GNU Lesser General Public License
 *              along with Agent Factory; see the file COPYING.  If not, write to
 *              the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 *              Boston, MA 02111-1307, USA.
 */

package com.agentfactory.platform.util;

import com.agentfactory.platform.core.InterpreterDescriptor;
import java.io.*;
import java.util.*;

import com.agentfactory.platform.service.PlatformServiceDescriptor;
import com.agentfactory.platform.core.PlatformGUIDescriptor;

/**
 * Read in an Agent Factory Platform Configurtion File.
 *
 * A platform configuration file specifies: (a) details of platform services to be
 * activated; (b) language and GUI plugins to be loaded; and (c) basic information
 * about the platform including its name.
 *
 * The PlatformConfigReader is instantiated by the AgentPlatform during start-up
 * and is disposed of once the Agent Platform is fully constructed.
 *
 * TODO - robertr - 25/08/04 - describe the syntax of a platform config file.
 *
 * The notions of default components, sleep time, and actuator threading are all
 * options passed to the interpreter.
 *
 * @author Terry Lowen
 * @author Robert Ross
 * @author Rem Collier
 */
public class PlatformConfigReader {
    /**
     * The class debug level.
     */
    public static final int CLASS_LOG_LEVEL = Logger.LEVEL_WARNING;
    public static final String UNKNOWN                              = "unknown";
    /**
     * The name of the agent platform.
     */
    private String name;
    
    /**
     * The list of services to be used on the platform.
     */
    private Vector services;
    
    /**
     * The list of platform GUIs to be activated for the platform.
     */
    private Vector platformGUIs;
    
    /**
     * A hashtable of interpreter plugins to be loaded. Key is the agent type,
     * while object is the subclass of Agent.
     */
    private Hashtable interpreters;
    
    /**
     * A hashtable of interpreter GUI plugins to be loaded. Key is the agent type,
     * while object is the subclass of AgentGUI.
     */
    private Hashtable agentGUIs;
        
    /**
     * The platform Domain.
     */
    private String platformDomain;
    
    /**
     * stores security policy settings
     */
    private Vector policies;
    
    
    private boolean debugStartup;
    
    /**
     * Do the basics of constructing the reader -- simply create the empty
     * containers, and set default values.
     *
     */
    private PlatformConfigReader() {
        services = new Vector();
        policies = new Vector();
        platformGUIs = new Vector();
        agentGUIs = new Hashtable();
        interpreters = new Hashtable();
        debugStartup=false;
        name = UNKNOWN;
    }
    
    /**
     * create a new configuration file reader using given file
     *
     * @param filename the name of the configuration file
     */
    public PlatformConfigReader(String filename) throws IOException {
        this();
        
        InputStream inStream = getClass().getResourceAsStream("/" + filename);
        
        // Check that the config file could be read properly
        if(inStream == null) {
            // Error : config file could not be read ... throw an excpetion
            throw new IOException("PlatformConfigReader() - could not load config file");
        }
        
        InputStreamReader streamReader = new InputStreamReader(inStream);
        BufferedReader  reader = new BufferedReader(streamReader);
        
        String line = null, command = null;
        StringTokenizer tok = null;
        while ((line = reader.readLine()) != null) {
            line = line.trim();
            if (line.length() != 0) {
                tok = new StringTokenizer(line);
                command = tok.nextToken();
                
                // This next section is where the platform configuration commands
                // are read!
                if (command.equals("SERVICE")) {
                    services.addElement(new PlatformServiceDescriptor(tok));
                    Logger.detail("PlatformConfigReader("+filename +") - adding service: "+ line, CLASS_LOG_LEVEL);
                } else if (command.equals("PLATFORM_DOMAIN")) {
                    platformDomain = tok.nextToken();
                } else if (command.equals("PLATFORM_NAME")) {
                    name = tok.nextToken();
                } else if (command.equals("AGENT_INTERPRETER")) {
                    buildInterpreterEntry(tok);
                } else if (command.equals("PLATFORM_GUI")) {
                    // An interpreter plugin is being specified.
                    String resource = tok.nextToken();
                    ArrayList parameters = new ArrayList();
                    while (tok.hasMoreTokens()) {
                        String parameter = tok.nextToken();
                        parameters.add(parameter);
                    }
                    platformGUIs.add(new PlatformGUIDescriptor(resource, parameters));
                } else if (command.equals("SECURITY_POLICY")) {
                    policies.add(line);
                } else {
                }
            }
        }
        
        reader.close();
        streamReader.close();
        inStream.close();
    }
    
    /**
     * Build an entry for an agent interpreter. All the elements are pulled from
     * the string tokenizer and packed into an InterpreterDescriptor object. This
     * object is then added to the hashtable of interpreters using the agent type
     * as key.
     *
     * Expected Syntax:
     *
     * <interpreter-class> <associated-type> <interprter-options>*
     *
     * @param tok
     */
    public void buildInterpreterEntry(StringTokenizer tok){
        String interpreterClass = tok.nextToken();
        String associatedType = tok.nextToken();
        
        Vector interpreterOptions = new Vector();
        while (tok.hasMoreTokens()) {
            interpreterOptions.add(tok.nextToken());
        }
        
        interpreters.put(associatedType,
                new InterpreterDescriptor(interpreterClass,
                                          associatedType,
                                          interpreterOptions));
    }
    
    /**
     * Get the hashtable of interpreters that were read in by the configuration
     * file reader.
     * @return Hashtable - the collection of all interpreters read in by
     * the input parser.
     */
    public Hashtable getInterpreters(){
        return this.interpreters;
    }
        
    public Vector getServices() {
        return services;
    }
    
    public Vector getPlatformGUIs(){
        return this.platformGUIs;
    }
    
    /**
     * This is used by the Platform Specific Actuator.
     */
    public String getName() {
        return name;
    }
    
    public String getPlatformDomain() {
        return platformDomain;
    }

    public Vector getSecurityPolicies() {
        return policies;
    }
}
